import { _decorator, Component, Enum, Label, RichText, Sprite, SpriteFrame } from 'cc';
import { EDITOR } from 'cc/env';

import EventExt from '../base/EventExt';
import { EVENT_KEY_CHANGE_LANGUAGE } from '../base/EventType';
import MutiLang from '../base/MutiLang';

const { ccclass, property, disallowMultiple } = _decorator;

// 文本组件类型
enum TxtType {
    label = 0,
    richTxt = 1,
}

/**
 * 多语言图片/文本 组件
 * --------------------------------
 * 用于文字的多语言显示(Label【普通文本文字】、Richtext【富文本文字】、Sprite【文字切图】)
 * 优先使用文字切图（效果较好看）
 * 其次普通文本(组件性能优于富文本)
 * 文本以及图片子控件，推荐设置为该节点的子节点
 */
@ccclass('MutiLangComp')
@disallowMultiple
export class MutiLangComp extends Component {

    // sprite节点
    @property({
        type: Sprite,
        displayName: "文本精灵",
        tooltip: "用于显示多语言文本图片的精灵组件",
    })
    private readonly sprite: Sprite = null;

    // 用于序列化EDITOR输入的值
    @property({ visible: false })
    private resName: string = "";
    // 文件资源路径
    @property({
        displayName: "文件名",
        tooltip: '多语言图片资源文件名（不带多语言后缀）！',
        visible() {
            return !!this.sprite;
        },
    })
    private get _resName() {
        return this.resName || this.defResName;
    }
    private set _resName(str: string) {
        this.resName = !!str ? str.trim() : this.defResName;
        this.updateSprite();
    }
    private get defResName(): string {
        return this.sprite ? this.sprite.node.name : '';
    }
    /** [拓展功能] 更换多语言图片对应基础文件名 */
    set imgResName(name: string) {
        this._imgResName = name;
        this._curLang = '';
        this.updateSprite();
    }
    get imgResName(): string {
        return this._imgResName || this._resName;
    }
    private _imgResName: string = '';


    // 用于序列化EDITOR输入的值
    @property({ visible: false })
    private bundleName: string = "";
    // 文件资源路径
    @property({
        displayName: "bundle名",
        tooltip: '分包的名称。不填值时，默认resources资源路径!',
        visible() {
            return !!this.sprite;
        },
    })
    private get _bundleName() {
        return this.bundleName || this.defBundle;
    }
    private set _bundleName(str: string) {
        this.bundleName = !!str ? str.trim() : this.defBundle;
        this.updateSprite();
    }
    private get defBundle(): string {
        return "resources";
    }

    // 文本类型
    @property({
        type: Enum(TxtType),
        displayName: "文本类型",
        tooltip: "用于显示多语言的文本类型",
    })
    private readonly txtType: TxtType = TxtType.label;

    // 普通文本组件
    @property({
        type: Label,
        displayName: "文本组件",
        tooltip: "用于显示多语言文字的普通文本组件",
        visible() {
            return this.txtType == TxtType.label;
        },
    })
    private readonly label: Label = null;

    // 富文本组件
    @property({
        type: RichText,
        displayName: "富文本组件",
        tooltip: "用于显示多语言文字的富文本组件",
        visible() {
            return this.txtType == TxtType.richTxt;
        },
    })
    private readonly richTxt: RichText = null;

    // 用于序列化EDITOR输入的值
    @property({ visible: false })
    private key: string = "";
    // 多语言具体键值支持'.'后链
    @property({
        displayName: "Key",
        tooltip: '多语言配置对应的键值链，以"."方式后链; 例如："lobby.dialog.title"',
        visible() {
            return (
                (this.txtType == TxtType.label && this.label) || (this.txtType == TxtType.richTxt && this.richTxt)
            );
        },
    })
    private get _key() {
        return this.key || this.defKey;
    }
    private set _key(str: string) {
        this.key = !!str ? str.trim() : this.defKey;
        this.updateLabel();
    }
    private get defKey(): string {
        return this.txtType == TxtType.label && this.label ? this.label.node.name
            : (this.txtType == TxtType.richTxt && this.richTxt ? this.richTxt.node.name
                : '');
    }
    /** [拓展功能] 更换多语言文本key */
    set txtKey(key: string) {
        this._txtKey = !!key ? key.trim() : '';
        this._curLang = '';
        this.updateLabel();
    }
    get txtKey(): string {
        return this._txtKey || this._key;
    }
    private _txtKey: string = '';


    // 当前资源标识(用于减少加载资源开销)
    private _curLang: string = '';
    // 是否需要重现渲染
    private _isImgDirty: boolean = true;
    private _isTxtDirty: boolean = true;

    onLoad() {
        EventExt.on(EVENT_KEY_CHANGE_LANGUAGE, (lang: string) => {
            MutiLang.init(lang);
            this.updateRender();
        }, this);
    }

    protected onDestroy(): void {
        EventExt.targetOff(this);
    }

    start() {
        this.updateRender();
    }

    onEnable(): void {
        if (this._isImgDirty)
            this.updateSprite();
        if (this._isTxtDirty)
            this.updateLabel();
    }

    /**
     * 更新多语言渲染
     */
    public updateRender() {
        if (!this || !this.isValid || this._curLang == MutiLang.curLang)
            return;
        // sprite
        this.updateSprite();
        // label
        this.updateLabel();
    }

    // 更新图片渲染
    private updateSprite() {
        const img: Sprite = this.sprite;
        if (!img || !img.isValid || EDITOR) return;

        if (this.node.activeInHierarchy) {
            // 减少不必要的更新开销
            if (this._curLang != MutiLang.curLang) {
                // 更新前，设置空纹理
                img.spriteFrame = null;
                MutiLang.loadSprite(this.imgResName, (frame: SpriteFrame, language?: string) => {
                    img.spriteFrame = frame;
                    this._curLang = language;
                    img.node.active = !!frame;
                }, this._bundleName);
            }
        }
        else {
            // 添加标识，延迟渲染
            this._isImgDirty = true;
        }
    }

    // 更新文本渲染
    public updateLabel() {
        const label: Label | RichText = this.txtType == TxtType.label ? this.label : this.richTxt;
        if (!label || !label.isValid || EDITOR) return;

        if (this.node.activeInHierarchy) {
            if (this._curLang != MutiLang.curLang) {
                label.string = MutiLang.getString(this.txtKey);
                this._curLang = MutiLang.curLang;
            }
        }
        else {
            // 添加标识，延迟渲染
            this._isTxtDirty = true;
        }
    }

}

